﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Tezzanator.Net.XNAGUI;
using Tezzanator.Net.XNAGUI.Controls;

namespace OpenST.GUI
{
    class Editor
    {
        Game game;
        CompositionRenderer comprender;

        Color[] NoteColors;
        Color[] NoteShades;

        bool ColorMode = true;
        int SelectedNote = 0;

        float pulse = 0;
        bool pulsestate = true;

        private List<PictureButton> ColorButtons;
        private PictureButton ModeButton;
        private Texture2D PanelBottom;
        private Texture2D PanelTop;
        private SpriteFont SongTitleFont;

        private bool LeftPrevPressed = false;

        private KeyboardInput KeyInput;

        private Tools.BaseTool CurrentTool;

        private PropertyWindow Tilepropertieswindow;
        private PropertyWindow CompoProperties;
            
        
        private struct TileStruct
        {
            public string Type;
            public Texture2D Texture;
            public PictureButton Button;
        }
        private List<TileStruct> AvailableTileList;
        int SelectedTileType = 0;

        public Editor(Game thegame, CompositionRenderer crend)
        {
            game = thegame;
            comprender = crend;
            ColorButtons = new List<PictureButton>();
            AvailableTileList = new List<TileStruct>();
            KeyInput = new KeyboardInput(thegame);

            Tilepropertieswindow = new PropertyWindow();
            Tilepropertieswindow.Text = "Tile Properties";

            CompoProperties = new PropertyWindow();
            CompoProperties.Text = "Composition Properties";
        }


        

        private void OpenComposition()
        {
            // TODO: Error Checking
            System.Windows.Forms.OpenFileDialog OpenDialog = new System.Windows.Forms.OpenFileDialog();
            OpenDialog.CheckFileExists = true;
            OpenDialog.Filter = "Song File|*.song";
            OpenDialog.ShowDialog();

            comprender.composition.Load(OpenDialog.FileName);

            
        }

        private void SaveComposition()
        {
            // TODO: Error Checking
            System.Windows.Forms.SaveFileDialog SaveDialog = new System.Windows.Forms.SaveFileDialog();
            SaveDialog.DefaultExt = ".song";
            SaveDialog.ShowDialog();

            comprender.composition.Save(SaveDialog.FileName);
        }

        public void NewComposition()
        {
            if (System.Windows.Forms.MessageBox.Show("Are you sure you want to clear your composition?", "New", System.Windows.Forms.MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
            {
                comprender.composition.NewComposition();
            }
        }

        public PictureButton AddButton(string Image, string Name, Vector2 Position)
        {
            PictureButton button = new PictureButton(game.Content.Load<Texture2D>(Image), Name);
            button.Position = Position;
            button.OnClick += new BaseControl.ControlEventHandler(ButtonClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(button);

            return button;
        }

        public void LoadContent()
        {
            // TODO: Make tools user selectable, Just a case of changing the CurrentTool Var...
            // Maybe change this to a struct much like the tile toolbox?
            CurrentTool = new Tools.DraggingPencil(comprender.composition, game);

            // Load the Pallete
            DataFormats.NoteColors Nc = game.Content.Load<DataFormats.NoteColors>("NoteColors");
            NoteColors = Nc.colors;
            NoteShades = Nc.shades;

            PanelBottom = game.Content.Load<Texture2D>("GUI Graphics/PanelBottom");
            PanelTop = game.Content.Load<Texture2D>("GUI Graphics/PanelTop");
            SongTitleFont = game.Content.Load<SpriteFont>("Fonts/SongTitleFont");

            // Load the available tile types, Construct a toolbox... Hmm
            DataFormats.TileList AvailableTiles = game.Content.Load<DataFormats.TileList>("Tiles/Tiles");
            int ty = 1;
            int tx = 1;
            for (int t = 0; t < AvailableTiles.TileTypes.Length; t++)
            {
                TileStruct newtile = new TileStruct();
                newtile.Type = AvailableTiles.TileTypes[t];
                newtile.Texture = game.Content.Load<Texture2D>(AvailableTiles.TileTextures[t]);
                newtile.Button = AddButton(AvailableTiles.TileTextures[t], "£" + t, new Vector2(320 + (16 * tx), (game.GraphicsDevice.Viewport.Height - (16 * ty)) - 8));
                newtile.Button.Size = newtile.Button.Size / 2;
                AvailableTileList.Add(newtile);
                if (ty == 1)
                {
                    ty = 2;
                }
                else
                {
                    ty = 1;
                    tx++;
                }
            }

            // Add the buttons...
            // Zoom
            AddButton("GUI Graphics/Function-ZoomIn", "Zoom In", new Vector2(game.GraphicsDevice.Viewport.Width - 60, game.GraphicsDevice.Viewport.Height - 40));
            AddButton("GUI Graphics/Function-ZoomOut", "Zoom Out", new Vector2(game.GraphicsDevice.Viewport.Width - 36, game.GraphicsDevice.Viewport.Height - 40));
            
            // File Options
            // New
            PictureButton NewCompButton = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/Gnome/Gnome-New"), "New");
            NewCompButton.Size = NewCompButton.Size / 2;
            NewCompButton.Position = new Vector2(2, 2);
            NewCompButton.OnClick += new BaseControl.ControlEventHandler(ButtonClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(NewCompButton);

            // Edit Title + Author
            PictureButton EditTitleAuthor = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/Gnome/Gnome-EditName"), "EditNameTitleThing");
            EditTitleAuthor.Size = EditTitleAuthor.Size / 2;
            EditTitleAuthor.Position = new Vector2(game.GraphicsDevice.Viewport.Width - 26, 2);
            EditTitleAuthor.OnClick += new BaseControl.ControlEventHandler(EditTitleAuthor_OnClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(EditTitleAuthor);


            // Open
            PictureButton OpenButton = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/Gnome/Gnome-Open"), "Open");
            OpenButton.Size = OpenButton.Size / 2;
            OpenButton.Position = new Vector2(NewCompButton.Size.X + 4, 2);
            OpenButton.OnClick += new BaseControl.ControlEventHandler(ButtonClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(OpenButton);

            // Save
            PictureButton SaveButton = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/Gnome/Gnome-save"), "Save");
            SaveButton.Size = SaveButton.Size / 2;
            SaveButton.Position = new Vector2((NewCompButton.Size.X + OpenButton.Size.X) + 6, 2);
            SaveButton.OnClick += new BaseControl.ControlEventHandler(ButtonClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(SaveButton);

            // Save
            PictureButton SavePNGButton = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/Gnome/Gnome-Stamp"), "SaveImage");
            SavePNGButton.Size = SavePNGButton.Size / 2;
            SavePNGButton.Position = new Vector2((NewCompButton.Size.X + OpenButton.Size.X + SaveButton.Size.X) + 6, 2);
            SavePNGButton.OnClick += new BaseControl.ControlEventHandler(ButtonClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(SavePNGButton);

            // ColButton
            int xpos = 12;
            int colnum = 0;
            foreach (Color col in NoteColors)
            {
                PictureButton button = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/ColourButton"), "!" + colnum);
                button.Position = new Vector2(xpos, game.GraphicsDevice.Viewport.Height - 40);
                button.ColorModifier = col;
                button.OnClick += new BaseControl.ControlEventHandler(ButtonClick);

                xpos += (int)button.Size.X;

                OpenST.GetComponent<Gui>(game).RootControl.AddChild(button);
                ColorButtons.Add(button);

                colnum++;
            }

            // Mode
            ModeButton = new PictureButton(game.Content.Load<Texture2D>("GUI Graphics/ShadeModeButton"), "Change Mode");
            ModeButton.Position = new Vector2(xpos, game.GraphicsDevice.Viewport.Height - 40);
            ModeButton.OnClick += new BaseControl.ControlEventHandler(ButtonClick);
            OpenST.GetComponent<Gui>(game).RootControl.AddChild(ModeButton);


            // Keyboard
            KeyInput.AddKeyEvent(Keys.OemMinus, new KeyboardInput.KeyPressEvent(comprender.ZoomOut));
            KeyInput.AddKeyEvent(Keys.OemPlus, new KeyboardInput.KeyPressEvent(comprender.ZoomIn));
            KeyInput.AddKeyEvent(Keys.Space, new KeyboardInput.KeyPressEvent(PlayPause));
        }

        void EditTitleAuthor_OnClick(BaseControl Sender)
        {
            CompoProperties.Show();
            CompoProperties.Properties.SelectedObject = comprender.composition;
            //throw new NotImplementedException();
        }

        public void PlayPause()
        {
            comprender.composition.Playing = !comprender.composition.Playing;

            if (comprender.composition.Playing == false)
            {
                comprender.composition.Reset();
            }
        }
         
        void SetShadeMode()
        {
            for (int i = 0; i < ColorButtons.Count; i++)
            {
                ColorButtons[i].ColorModifier = NoteShades[i];
                ColorMode = false;
                ModeButton.Picture = game.Content.Load<Texture2D>("GUI Graphics/ColourModeButton");
            }
        }

        void SetColorMode()
        {
            for (int i = 0; i < ColorButtons.Count; i++)
            {
                ColorButtons[i].ColorModifier = NoteColors[i];
                ColorMode = true;
                ModeButton.Picture = game.Content.Load<Texture2D>("GUI Graphics/ShadeModeButton");
            }
        }

        void ChangeMode()
        {
            if (ColorMode == true)
            {
                SetShadeMode();
            }
            else
            {
                SetColorMode();
            }
        }

        void ButtonClick(BaseControl Sender)
        {
            switch (Sender.Name)
            {
                case "Zoom In":
                    comprender.ZoomIn();
                    break;
                case "Zoom Out":
                    comprender.ZoomOut();
                    break;
                case "Change Mode":
                    ChangeMode();
                    break;
                case "Open":
                    OpenComposition();
                    break;
                case "Save":
                    SaveComposition();
                    break;
                case "New":
                    NewComposition();
                    break;
                case "SaveImage":
                    comprender.composition.SavePNG("e.png");
                    break;
            }

            // The colour buttons names are "!1" "!2" Etc.
            if (Sender.Name.StartsWith("!"))
            {
                SelectedNote = Convert.ToInt32(Sender.Name.TrimStart('!'));
            }

            // The Tile Selection button's names are "£1", "£2" Etc.
            if (Sender.Name.StartsWith("£"))
            {
                SelectedTileType = Convert.ToInt32(Sender.Name.TrimStart('£'));
            }
        }

        private void DoPulse(GameTime gameTime)
        {
            // Create a pulse, Shows what is selected!
            if (pulsestate == true)
            {
                pulse += (float)gameTime.ElapsedGameTime.Milliseconds / 1000;
            }
            else
            {
                pulse -= (float)gameTime.ElapsedGameTime.Milliseconds / 1000;
            }

            //game.Window.Title = pulse.ToString();

            if (pulse >= 1.0f)
            {
                pulsestate = false;
            }
            if (pulse <= 0.5f)
            {
                pulsestate = true;
            }

            pulse = MathHelper.Clamp(pulse, 0.5f, 1f);
        }

        public void Update(GameTime gameTime)
        {
            KeyInput.Update();
            DoPulse(gameTime);

            KeyboardState keystate = Keyboard.GetState();

            // Selected note button pulse
            for (int i = 0; i < ColorButtons.Count; i++)
            {
                if (i == SelectedNote)
                {
                    ColorButtons[i].ColorModifier.A = (byte)(pulse * 255);
                    
                }
                else
                {
                    ColorButtons[i].ColorModifier.A = (byte)255;
                }
            }

            // Selected tool pulse!
            // First reset them all to full alpha
            foreach (TileStruct Ts in AvailableTileList)
            {
                if(ColorMode)
                {
                    Ts.Button.ColorModifier = NoteColors[SelectedNote];
                }else{
                    Ts.Button.ColorModifier = NoteShades[SelectedNote];
                }
            }
            // Then reset the alpha on the selected tool, Simple.
            AvailableTileList[SelectedTileType].Button.ColorModifier.A = (byte)(pulse *255);

            // ---
            // Now for the part for interacting with the tiles, Oh god.

            // If the Gui caught the mouse then obviously with this being behind it, interaction should cease!
            if (OpenST.GetComponent<Gui>(game).InputWasCaught == false && game.IsActive == true)
            {
                MouseState mousestate = Mouse.GetState();
                int x = 0;
                int y = 0;

                x = (mousestate.X - (int)comprender.Origin.X) / (int)((float)CompositionRenderer.BaseTileSize * comprender.Zoom);
                y = (mousestate.Y - (int)comprender.Origin.Y) / (int)((float)CompositionRenderer.BaseTileSize * comprender.Zoom);

                x = (int)MathHelper.Clamp(x, 0, Composition.CompositionMaxSizeX - 1);
                y = (int)MathHelper.Clamp(y, 0, Composition.CompositionMaxSizeY - 1);

                
                if(keystate.IsKeyDown(Keys.LeftControl))
                {
                    if (mousestate.LeftButton == ButtonState.Pressed && LeftPrevPressed == false)
                    {
                       Tilepropertieswindow.Show();
                       Tilepropertieswindow.Properties.SelectedObject = new DictionaryPropertyGridAdapter(comprender.composition.Tiles[x, y].TileData);
                       Tilepropertieswindow.Properties.Refresh();
                    }

                    if (mousestate.LeftButton == ButtonState.Released)
                    {
                       LeftPrevPressed = false;
                    }
                }
                else
                {

                    if (mousestate.LeftButton == ButtonState.Pressed && LeftPrevPressed == false)
                    {

                        CurrentTool.MouseDown(x, y, SelectedNote, AvailableTileList[SelectedTileType].Type, ColorMode);
                        LeftPrevPressed = true;
                    }
                    CurrentTool.Update(x, y, SelectedNote, AvailableTileList[SelectedTileType].Type, ColorMode);
                    

                    if (mousestate.LeftButton == ButtonState.Released)
                    {
                        CurrentTool.MouseUp(x, y, SelectedNote, AvailableTileList[SelectedTileType].Type, ColorMode);
                        LeftPrevPressed = false;
                    }
                }
            }
        }

        public void Draw(GameTime gameTime)
        {
            SpriteBatch spritebatch = new SpriteBatch(game.GraphicsDevice);
            spritebatch.Begin();

            // Tool Panel
            spritebatch.Draw(PanelBottom, new Rectangle(
                0,
                (int)game.GraphicsDevice.Viewport.Height - 50,
                (int)game.GraphicsDevice.Viewport.Width,
                50), new Color(120,120,120, 230));

            // Top Menu Panel
            spritebatch.Draw(PanelTop, new Rectangle(
                0,
                0,
                (int)game.GraphicsDevice.Viewport.Width,
                30), new Color(120, 120, 120, 230));

            // Song Title
            string TotalString = comprender.composition.Title + " - " + comprender.composition.Author;
            int Width = (int)SongTitleFont.MeasureString(TotalString).X;
            spritebatch.DrawString(SongTitleFont, TotalString, new Vector2(
                (game.GraphicsDevice.Viewport.Width / 2) - (Width / 2),
                2), Color.White);

            spritebatch.End();
        }
    }
}
